/**************************************************************
  > File Name: myls.c
  > Author: LuoLiang
  > Mail: 1204553475@qq.com 
  > Created Time: 2022年01月08日 星期六 13时09分11秒
 **************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <glob.h>
#include <time.h>

#define SIZE 1024

/* 获取文件类型 */
static char getFileType(struct stat *statbuf)
{
	switch (statbuf->st_mode & S_IFMT)
	{
		case S_IFREG:
			return '-';
		case S_IFDIR:
			return 'd';
		case S_IFSOCK:
			return 's';
		case S_IFBLK:
			return 'b';
		case S_IFIFO:
			return 'F';
		default:
			return '?';
	}
}

/* 获取权限信息 */
static char *getPermission(struct stat *statbuf)
{
	char *buf;
	int i, k = 0;

	buf = calloc(9,sizeof(char));
	if (buf == NULL)
	{
		fprintf(stderr,"calloc() fail\n");
		exit(1);
	}

	for (i = 0; i < 9; i++)
		buf[i] = '-';

	if (statbuf->st_mode & S_IRUSR)
			buf[k] = 'r';
	if (statbuf->st_mode & S_IWUSR)
			buf[k+1] = 'w';
	if (statbuf->st_mode & S_IXUSR)
			buf[k+2] = 'x';

	if (statbuf->st_mode & S_IRGRP)
			buf[k+3] = 'r';
	if (statbuf->st_mode & S_IWGRP)
			buf[k+4] = 'w';
	if (statbuf->st_mode & S_IXGRP)
			buf[k+5] = 'x';

	if (statbuf->st_mode & S_IROTH)
			buf[k+6] = 'r';
	if (statbuf->st_mode & S_IWOTH)
			buf[k+7] = 'w';
	if (statbuf->st_mode & S_IXOTH)
			buf[k+8] = 'x';

	return buf;
}

/* 获取uname */
static char *getUsrname(int uid)
{
	struct passwd *uid_line;
	uid_line = getpwuid(uid);
	if (uid_line == NULL)
	{
		perror("getpwuid()");
		exit(1);
	}
	return uid_line->pw_name;
}

/* 获取gname */
static char *get_Gropname(int gid)
{
	struct group *gid_line;
	gid_line = getgrgid(gid);
	if (gid_line == NULL)
	{
		perror("getpwuid()");
		exit(1);
	}
	return gid_line->gr_name;
}
/* 获取文件去掉绝对路径的名字 */
static char *getRealName(char *pathname)
{
	char *pos = NULL;
	pos = strrchr(pathname,'/');
	if (pos)
		return pos+1;
	return pathname;
}

/*
static int Judge_loop(char *pathname)
{
	char *pos = NULL;
	pos = strrchr(pathname,'/');
	if (strcmp(pos+1,".") == 0 || strcmp(pos+1,"..") == 0)
		return 0;
	return 1;
}
*/

/* 根据参数打印文件属性 */
static void PrintFileNature(char *pathname,char *optbuf,struct stat *statbuf)
{
	char *pms_ret = NULL;
	char *uid_ret = NULL;
	char *gid_ret = NULL;
	char *newname = NULL;
	char type;
	/* 将mtime改为本地时间 */
	struct tm *t = localtime(&statbuf->st_mtime);

	pms_ret = getPermission(statbuf);
	newname = getRealName(pathname);
	type = getFileType(statbuf);

	if (optbuf[0] == 'l' && optbuf[2] != 'n')
	{
		uid_ret = getUsrname(statbuf->st_uid);
		gid_ret = get_Gropname(statbuf->st_gid);
		printf("%c%s %2ld %-4s %-4s %6ld %-2d月 %-2d %2d:%2d %-s\n",type,pms_ret,statbuf->st_nlink,uid_ret,gid_ret,\
							statbuf->st_size,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,newname);
	}

	if (optbuf[1] == 'a' && optbuf[0] != 'l' && optbuf[2] != 'n')
	{
		puts(newname);
	}

	if (optbuf[2] == 'n')
	{
		printf("%c%s %2ld %-4d %-4d %-6ld %-2d月 %-2d %2d:%2d %-s\n",type,pms_ret,statbuf->st_nlink,statbuf->st_uid,\
							statbuf->st_gid,statbuf->st_size,(t->tm_mon)+1,t->tm_mday,t->tm_hour,t->tm_min,newname);
	}
	if (optbuf[0] == 0 && optbuf[1] == 0 && optbuf[2] == 0)
		printf("%s\n",newname);
}

/* 获取文件夹里面文件的信息 */
static void getDirMsg(char *pathname,char *optbuf)
{
	int l_ret;
	struct stat statbuf;

	l_ret = lstat(pathname,&statbuf);
	if (l_ret < 0)
	{
		perror("lstat()");
		exit(1);
	}
	
	PrintFileNature(pathname,optbuf,&statbuf);
}
/* 通过文件类型进行对应操作 */
static void key_ls(char *pathname,char *optbuf)
{
	int l_ret;
	struct stat statbuf;
	char pattern[SIZE] = {0};
	glob_t line;

	l_ret = lstat(pathname,&statbuf);
	if (l_ret < 0)
	{
		perror("lstat()");
		exit(1);
	}
	/* 如果是文件，直接打印属性信息 */
	if (S_ISREG(statbuf.st_mode))
	{
		PrintFileNature(pathname,optbuf,&statbuf);
		return ;
	}

	/* 如果是文件夹，获取文件夹下的文件 */
	if(S_ISDIR(statbuf.st_mode))
	{
		/* 文件隐藏文件匹配 */
		if (optbuf[1] == 'a')
		{
			strncpy(pattern,pathname,SIZE);
			strncat(pattern,"/.",SIZE-1);
			glob(pattern,0,NULL,&line);

			strncpy(pattern,pathname,SIZE);
			strncat(pattern,"/..",SIZE-1);
			glob(pattern,GLOB_APPEND,NULL,&line);
		}

		strncpy(pattern,pathname,SIZE);
		strncat(pattern,"/*",SIZE-1);
		if (optbuf[1] == 'a')
			glob(pattern,GLOB_APPEND,NULL,&line);
		else
			glob(pattern,0,NULL,&line);

		for (int i = 0; i < line.gl_pathc; i++)
		{
			getDirMsg(line.gl_pathv[i],optbuf);
		}
		globfree(&line);
	}
	else
		return ;
	return ;
}

/* 根据文件名匹配 */
void func(char **pathname,char *optbuf)
{
	int i, k = 0;
	if (pathname[0] == NULL)
	{
		pathname[0] = "./";	
	}

	for (i = 0; pathname[i]; i++)
	{
		if (k++)
			printf("\n");
		key_ls(pathname[i],optbuf);
	}
}

int main(int argc,char **argv)
{
	int opt;
	int flag = 1;
	int k = 0;
	char *pathname[SIZE];
	char optbuf[3] = {0};
	while ((opt = getopt(argc,argv,"-lan")) != -1)
	{
		flag = 0;
		switch (opt)
		{
			case 1:
				pathname[k++] = argv[optind-1];	
				break;
		//-l
			case 'l':
				optbuf[0] = 'l';  
				break;
		//-a
			case 'a':
				optbuf[1] = 'a';  
				break;
		//-n
			case 'n':
				optbuf[2] = 'n';
				break;
		}
	}
	/* 未输入路径，默认为当前路径 */
	if (flag)
		pathname[k++] = "./";

	func(pathname,optbuf);
    exit(0);
}
